#include <unistd.h>
#include <dirent.h>
#include <iostream>
using namespace std;
#include <string>
#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>



// 1:ls功能的实现
void print_err(char *message)
{
    printf("%s 的使用需要2个参数\n", message);
}
int m1(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *dirp;
    if (argc != 2)
    {
        print_err(argv[0]);
    }
    if ((dp = opendir(argv[1])) == nullptr)
    {
        cout << "不能打开此文件" << argv[1] << endl;
    }

    while ((dirp = readdir(dp)) != nullptr)
    {
        printf("%s\n", dirp->d_name);
    }

    closedir(dp);

    return 0;
}

// 2:复制文件的功能实现
// 2.1：不带缓存的io
#define BUFFSIZE 4096
int m2(void)
{
    int n;
    char buffer[BUFFSIZE];

    while ((n = read(STDIN_FILENO, buffer, BUFFSIZE)) > 0)
    { // 从标准输入中读取数据到buffer中
        if (write(STDOUT_FILENO, buffer, n) != n)
        { // 然后将buffer中的数据写入到标准输出中
            printf("write errno\n");
        }
    }

    if (n < 0)
    {
        printf("read errno\n");
    }

    return 0;
}

// 2.2：标准io
int m3()
{
    int c;
    string line;
    while ((c = getc(stdin)) != EOF)
    {
        if (putc(c, stdout) == EOF)
        {
            printf("out errno\n");
        }
    }
    if (ferror(stdin))
    {
        printf("in errno\n");
    }

    return 0;
}

// 3:shell程序的基本实现
static void handler(int signo)
{
    cout << "捕获到的信号:" << signo << endl;
}
int m4()
{
    if (signal(2, handler) == SIG_ERR)
    {
        perror("signal errno\n");
    }
    char buffer[BUFFSIZE];
    pid_t id;
    int status;

    printf("%% ");
    while (fgets(buffer, BUFFSIZE, stdin) != nullptr)
    {
        // exec函数是以null结尾的
        if (buffer[strlen(buffer) - 1 == '\n'])
            buffer[strlen(buffer) - 1] = 0; // 如果最后一个字符是换行，那么把他置换为0

        // 让子进程去执行shell操作
        if ((id = fork()) < 0)
        {
            cout << "fork errno" << endl;
            exit(0);
        }
        else if (id == 0)
        {
            // child process
            execlp(buffer, buffer, (char *)0);
            printf("could exec %s", buffer);
            exit(1);
        }
        // parent process
        if ((id == waitpid(id, &status, 0)) < 0)
        {
            cout << "wait errno" << endl;
        }
    }
    return 0;
}

#define NUM 10
typedef void (*func_t)();
func_t handlerTask[NUM];
// 样例任务
void task1()
{
    printf("handler task1\n");
}
void task2()
{
    printf("handler task2\n");
}
void task3()
{
    printf("handler task3\n");
}
void task4()
{
    printf("handler task4\n");
}

void loadTask()
{
    memset(handlerTask, 0, sizeof(handlerTask));
    handlerTask[0] = task1;
    handlerTask[1] = task2;
    handlerTask[2] = task3;
    handlerTask[3] = task4;
}

// 4:非阻塞式轮询等待
int main()
{
    loadTask(); // 初始化数组
    pid_t id = fork();
    int n = 5;
    if (id == 0)
    {
        // child
        while (n--)
        {
            cout << "我是子进程" << endl;
            if (n == 0)
                exit(1);
            sleep(1);
        }
    }
    // parent
    int status;
    while (1)
    {
        pid_t ret = waitpid(id, &status, WNOHANG);
        if (ret == 0)
        {
            // wait调用成功，但是子进程没有退出
            // 可以做其他的事情
            printf("wait done,but child process is running..\n");
            for (int i = 0; handlerTask[i] != nullptr; i++)
            {
                handlerTask[i](); // 回调
            }
        }
        else if (ret > 0)
        {
            // 子进程退出了
            printf("wait success exit code:%d,sig %d\n", (status >> 8) & 0xFF, status & 0x7F);
            break;
        }
        else
        {
            printf("waitpid call errno\n");
            break;
        }
        sleep(1);
    }

    return 0;
}

// test getpid
int m6()
{
    printf("我是一个进程，我的pid是：%d", getpid());
    return 0;
}

// 创建一个具有空洞的文件
char buffer1[] = "abcdefghij";
char buffer2[] = "ABCDEFGHIJ";

int m7()
{
    umask(0);
    int fd;
    if ((fd = creat("file.hole", 0666) < 0))
    {
        perror("creat errno\n");
    }

    if (write(fd, buffer1, 10) != 10)
    {
        perror("write errno\n");
    }

    if (lseek(fd, 16384, SEEK_CUR) == -1)
    {
        perror("lseek errno\n");
    }

    if (write(fd, buffer2, 10) != 10)
    {
        perror("write errno\n");
    }
    // offset = 16394

    return 0;
}


